/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.treepoke.util.ws;

import com.treepoke.util.dto.WebServiceDTO;
import com.treepoke.util.logging.CRCCLogger;
import com.treepoke.util.properties.TPConstant;
import com.sun.org.apache.xerces.internal.parsers.DOMParser;
import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

/**
 * Clase que encapsula toda la implementacion para invocar Servicios WEB de
 * manera dinamica.
 *
 */
public class WSDispatchClient {

    private static CRCCLogger logger = CRCCLogger.getLogger(TPConstant.getNOMBRE_APLICACION());

    /**
     * Invoca un WebService con la informacion de punto final definida. Se usa
     * el mensaje request entregado.
     *
     * @param requestMessage Request a realizar al servicio
     * @return Nodo (org.w3c.dom.Node) que contiene la informacion de Respuesta
     * entregada. Se omite la informacion Envelope, Header, Attachments, etc.
     *
     * @throws SOAPException Posibles errores que se presentan.
     */
    public static Node invoke(WebServiceDTO webServiceDTO, String requestMessage) throws SOAPException {

        QName serviceName = new QName(webServiceDTO.getNamespace(), webServiceDTO.getNombreServicio());
        QName portName = new QName(webServiceDTO.getNamespace(), webServiceDTO.getNombrePuerto());

        Service service = Service.create(serviceName);
        service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, webServiceDTO.getEndpointUrl());

        Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class,
                Service.Mode.MESSAGE);

        SOAPMessage request = createRequest(requestMessage);

        try {
            SOAPMessage response = dispatch.invoke(request);
            SOAPBody bodyRes = response.getSOAPBody();
            return bodyRes.getFirstChild();

        } catch (SOAPFaultException e) {
            if (e.getFault() != null && e.getFault().getDetail() != null) {
                return e.getFault().getDetail().getFirstChild();
            }
            logger.errorMessage("Error WSDispatchClient.invoke " + webServiceDTO.getNombreOperacion()+e.getMessage(), e);
            throw new SOAPException("Error WSDispatchClient.invoke " + e.getMessage(), e);
        } catch(Exception ex){
            logger.errorMessage("Error WSDispatchClient.invoke " + webServiceDTO.getNombreOperacion()+ ex.getMessage(), ex);
            throw new SOAPException("Error WSDispatchClient.invoke " + ex.getMessage(), ex);
        }
    }

    /**
     * Crea un SOAP request con el mensaje enviado.
     *
     * @param requestMessage Cadena XML con el mensaje request a enviar.
     * @return Mensaje SOAP con request listo para enviar
     * @throws SOAPException Posible error presentado al construir mensaje SOAP
     */
    private static SOAPMessage createRequest(String requestMessage) throws SOAPException {

        SOAPMessage request = MessageFactory.newInstance().createMessage();
        SOAPPart part = request.getSOAPPart();
        SOAPEnvelope env = part.getEnvelope();

        SOAPBody body = env.getBody();
        DOMParser parser = new DOMParser();

        try {
            parser.parse(new InputSource(new java.io.StringReader(requestMessage)));
        } catch (Exception e) {
            logger.debugMessage("El parametro RequestMessage no es Valido o no puede ser leido. " + e);
        }
        body.addDocument(parser.getDocument());

        request.saveChanges();
        return request;
    }
}
